package com.nineclock.sign.service.Impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Joiner;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.entity.Result;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.filter.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.sign.dto.SignInfoDTO;
import com.nineclock.sign.dto.SignResponseDTO;
import com.nineclock.sign.dto.SignRsponseListDTO;
import com.nineclock.sign.dto.SignsDTO;
import com.nineclock.sign.excel.CustomHandler;
import com.nineclock.sign.mapper.SignInfoMapper;
import com.nineclock.sign.mapper.SignPictureMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.pojo.SignPicture;
import com.nineclock.sign.service.SignInfonService;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysDepartmentDTO;
import com.nineclock.system.feign.SysCompanyUserFeign;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class SignInfonServiceImpl implements SignInfonService {

    @Autowired
    private SignInfoMapper signInfoMapper;

    @Autowired
    private SignPictureMapper signPictureMapper;

    @Autowired
    private SysCompanyUserFeign companyUserFeign;

    @Autowired
    private RedisTemplate redisTemplate;



    /**
     * 接口名称：PC: 查询签到列表
     * Tag ：签到服务
     * 接口路径：GET/sign/sign
     */
    @Override
    public PageResult<SignInfoDTO> querySigns(String startTime, String endTime, Integer page, Integer pageSize) {
        //非空处理
        if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //获取时间段
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);
        //根据用户id进行分页查询分组
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.groupBy(SignInfo::getCompanyUserId);
        wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.between(SignInfo::getCreateDate, startTime, endTime);
        wrapper.select(SignInfo::getCompanyUserId);

        IPage<SignInfo> ipage = new Page<>(page, pageSize);
        ipage = signInfoMapper.selectPage(ipage, wrapper);
        //获取当前页的数据
        List<SignInfo> signInfoList = ipage.getRecords();
        //取出当前页的id
        List<Long> ids = new ArrayList<>();
        for (SignInfo signInfo : signInfoList) {
            ids.add(signInfo.getCompanyUserId());
        }

        //根据id查公司信息 如果存在存id进去
        //有效id
        List<Long> idsNew = new ArrayList<>();
        for (Long id : ids) {
            SysCompanyUserDTO sysCompanyUserDTO = companyUserFeign.queryCompanyUserById(id).getData();
            if (sysCompanyUserDTO != null) {
                idsNew.add(id);
            }
        }

        //若ids不为空 开始存进dto
        if (!CollectionUtils.isEmpty(idsNew)) {
            List<SignInfoDTO> signInfoDTOS = idsNew.stream().map(id -> {

                SignInfoDTO signInfoDTO = new SignInfoDTO();

                SysCompanyUserDTO sysCompanyUserDTO = companyUserFeign.queryCompanyUserById(id).getData();

                if (sysCompanyUserDTO != null) {
                    signInfoDTO.setId(sysCompanyUserDTO.getId());
                    signInfoDTO.setPost(sysCompanyUserDTO.getPost());
                    signInfoDTO.setUsername(sysCompanyUserDTO.getUserName());
                    signInfoDTO.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
                    SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
                    sysDepartmentDTO.setId(sysCompanyUserDTO.getDepartmentId());
                    sysDepartmentDTO.setName(sysCompanyUserDTO.getDepartmentName());

//                    signInfoDTO.setDepartment(sysDepartmentDTO);
                    signInfoDTO.setDepartment(sysDepartmentDTO);

                    //时间段进行遍历 把他存进去
                    List<SignsDTO> signsDTOS = spanDateList.stream().map(everyday -> {
                        SignsDTO signsDTO = new SignsDTO();
                        //把当前的日期添加进去
                        signsDTO.setSignDate(everyday);
                        //查询当前日期的签到数
                        LambdaQueryWrapper<SignInfo> wrapperDate = new LambdaQueryWrapper<>();
                        wrapperDate.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
                        wrapperDate.eq(SignInfo::getCreateDate, everyday);
                        Integer count = signInfoMapper.selectCount(wrapperDate);
                        if (count == 0) {
                            signsDTO.setSignCount(0);
                        } else {
                            signsDTO.setSignCount(count);
                        }

                        return signsDTO;

                    }).collect(Collectors.toList());

                    signInfoDTO.setSigns(signsDTOS);
                }
                return signInfoDTO;

            }).collect(Collectors.toList());

            return new PageResult<>(ipage.getTotal(), ipage.getPages(), signInfoDTOS);
        }
        return new PageResult<>(ipage.getTotal(), ipage.getPages(), null);

    }

    /**
     * 接口名称：PC: 导出签到列表
     * Tag ：签到服务
     * 接口路径：GET/sign/export
     */
    @Override
    public void exportSignInfo(String startTime, String endTime) throws Exception {

        // 查询签到数据
        List<SignInfoDTO> signInfoDTOList = this.querySignIn(startTime, endTime);

        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        response.setHeader("Content-disposition", "attachment;filename=Attendance.xls");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setCharacterEncoding("utf-8");

        // 生成excel文件，下载
        EasyExcel.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLS)// 文件格式
                .head(this.handleHeaders(signInfoDTOList)) //表头
                .registerWriteHandler(this.horizontalCellStyleStrategy())//设置样式
                .registerWriteHandler(new CustomHandler())//设置样式
                .sheet(0)
                .doWrite(this.handleData(signInfoDTOList));//数据行
    }

    /**
     * 动态构造表头
     *
     * @param signInfoDTOList
     * @return
     */
    private List<List<String>> handleHeaders(List<SignInfoDTO> signInfoDTOList) {
        List<List<String>> headers = new ArrayList<>();
        if (!CollectionUtils.isEmpty(signInfoDTOList)) {
            headers.add(Arrays.asList("姓名"));
            headers.add(Arrays.asList("工号"));
            headers.add(Arrays.asList("部门"));
            headers.add(Arrays.asList("职位"));

            if (!CollectionUtils.isEmpty(signInfoDTOList)) {
                SignInfoDTO signInfoListDTO = signInfoDTOList.get(0);
                List<SignsDTO> signs = signInfoListDTO.getSigns();
                if (!CollectionUtils.isEmpty(signs)) {
                    for (SignsDTO sign : signs) {
                        headers.add(Arrays.asList(sign.getSignDate()));
                    }
                }
            }
        }
        return headers;
    }

    /**
     * 动态构造每一行数据
     *
     * @param signInfoDTOList
     * @return
     */
    private List<List<String>> handleData(List<SignInfoDTO> signInfoDTOList) {
        List<List<String>> dataList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(signInfoDTOList)) {
            for (SignInfoDTO signInfoListDTO : signInfoDTOList) {
                List<String> row = new ArrayList<>();

                row.add(signInfoListDTO.getUsername());
                row.add(signInfoListDTO.getWorkNumber());
                row.add(signInfoListDTO.getDepartment().getName());
                row.add(signInfoListDTO.getPost());

                // 每一行考勤数据
                List<SignsDTO> signs = signInfoListDTO.getSigns();
                if (!CollectionUtils.isEmpty(signs)) {
                    for (SignsDTO sign : signs) {
                        row.add(sign.getSignCount().toString());
                    }
                }
                dataList.add(row);
            }
        }
        return dataList;

    }

    /**
     * 设置样式
     */
    public HorizontalCellStyleStrategy horizontalCellStyleStrategy() {

        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //内容策略 - 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("阿里巴巴普惠体");
        font.setFontHeightInPoints((short) 11);
        contentWriteCellStyle.setWriteFont(font);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(contentWriteCellStyle, contentWriteCellStyle);

        return horizontalCellStyleStrategy;
    }

    /**
     * 查询指定时间段内的签到列表数据
     *
     * @param startTime
     * @param endTime
     * @return
     */
    private List<SignInfoDTO> querySignIn(String startTime, String endTime) {

        //非空处理
        if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //获取时间段
        List<String> spanDateList = DateTimeUtil.getSpanDateList(startTime, endTime);
        //根据用户id进行分页查询分组
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.groupBy(SignInfo::getCompanyUserId);
        wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.between(SignInfo::getCreateDate, startTime, endTime);
        wrapper.select(SignInfo::getCompanyUserId);
        List<SignInfo> signInfoList = signInfoMapper.selectList(wrapper);
        List<Long> ids = new ArrayList<>();
        for (SignInfo signInfo : signInfoList) {
            ids.add(signInfo.getCompanyUserId());
        }
        //根据id查公司信息 如果存在存id进去
        //有效id
        List<Long> idsNew = new ArrayList<>();
        for (Long id : ids) {
            SysCompanyUserDTO sysCompanyUserDTO = companyUserFeign.queryCompanyUserById(id).getData();
            if (sysCompanyUserDTO != null) {
                idsNew.add(id);
            }
        }

        //若ids不为空 开始存进dto
        if (!CollectionUtils.isEmpty(idsNew)) {
            List<SignInfoDTO> signInfoDTOS = idsNew.stream().map(id -> {

                SignInfoDTO signInfoDTO = new SignInfoDTO();

                SysCompanyUserDTO sysCompanyUserDTO = companyUserFeign.queryCompanyUserById(id).getData();
                if (sysCompanyUserDTO != null) {
                    signInfoDTO.setId(sysCompanyUserDTO.getId());
                    signInfoDTO.setPost(sysCompanyUserDTO.getPost());
                    signInfoDTO.setUsername(sysCompanyUserDTO.getUserName());
                    signInfoDTO.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
                    SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
                    sysDepartmentDTO.setId(sysCompanyUserDTO.getDepartmentId());
                    sysDepartmentDTO.setName(sysCompanyUserDTO.getDepartmentName());

                    signInfoDTO.setDepartment(sysDepartmentDTO);

                    //时间段进行遍历 把他存进去
                    List<SignsDTO> signsDTOS = spanDateList.stream().map(everyday -> {
                        SignsDTO signsDTO = new SignsDTO();
                        //把当前的日期添加进去
                        signsDTO.setSignDate(everyday);
                        //查询当前日期的签到数
                        LambdaQueryWrapper<SignInfo> wrapperDate = new LambdaQueryWrapper<>();
                        wrapperDate.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
                        wrapperDate.eq(SignInfo::getCreateDate, everyday);
                        Integer count = signInfoMapper.selectCount(wrapperDate);
                        if (count == 0) {
                            signsDTO.setSignCount(0);
                        } else {
                            signsDTO.setSignCount(count);
                        }

                        return signsDTO;

                    }).collect(Collectors.toList());

                    signInfoDTO.setSigns(signsDTOS);
                }
                return signInfoDTO;

            }).collect(Collectors.toList());
            return signInfoDTOS;

        }
        return null;
    }


    /**
     * 查询员工指定日期签到记录列表
     * @param dateStr
     * @return
     */
    @Override
    public List<SignRsponseListDTO> listSignAllUser(String dateStr) {

        //查询出本公司所有人签到记录
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SignInfo::getCreateDate,dateStr);
        List<SignInfo> infoList = signInfoMapper.selectList(wrapper);

        ArrayList<SignRsponseListDTO> signRsponseListDTOS = new ArrayList<>();//所有员工和对应签到记录集合

        //再根据员工id分组
        Map<Long, List<SignInfo>> listMap = infoList.stream().collect(Collectors.groupingBy(SignInfo::getCompanyUserId));

        //遍历集合,每遍历一个就是一个用户的签到记录
        for (Map.Entry<Long, List<SignInfo>> entry : listMap.entrySet()) {
            SignRsponseListDTO signRsponseListDTO = new SignRsponseListDTO();

            //调用feign接口用员工信息查询员工信息
            SysCompanyUserDTO companyUserDTO = companyUserFeign.queryCompanyUserById(entry.getKey()).getData();

            if(companyUserDTO!=null){
                //设置用户姓名
                signRsponseListDTO.setUsername(companyUserDTO.getUserName());

                ArrayList<SignResponseDTO> signResponseDTOS = new ArrayList<>();
                //获取ResponseDTO集合
                for (SignInfo signInfo : entry.getValue()) {
                    SignResponseDTO responseDTO = BeanHelper.copyProperties(signInfo, SignResponseDTO.class);

                    //从redis中获取当日和当月签到次数
                    String dayCountKey = CurrentUserHolder.get().getCompanyId() + "," + CurrentUserHolder.get().getCompanyUserId() + "," + signInfo.getCreateDate();
                    String dayCount = (String) redisTemplate.opsForValue().get(dayCountKey);

                    String monthCountKey = CurrentUserHolder.get().getCompanyId() + "," + CurrentUserHolder.get().getCompanyUserId() + "," + signInfo.getCreateMonth();
                    String monthCount = (String) redisTemplate.opsForValue().get(monthCountKey);

                    responseDTO.setDayCount(dayCount);
                    responseDTO.setMonthCount(monthCount);
                    responseDTO.setUsername(companyUserDTO.getUserName());

                    //时间处理
                    String dateString = DateTimeUtil.dateToStr(signInfo.getCreateTime(), DateTimeUtil.TIME_FORMAT_1);
                    responseDTO.setCreateTime(dateString);

                    //查询签到图片列表
                    LambdaQueryWrapper<SignPicture> wrapper1 = new LambdaQueryWrapper<>();
                    wrapper1.eq(SignPicture::getSignId,signInfo.getId());
                    List<SignPicture> signPictures = signPictureMapper.selectList(wrapper1);
                    List<String> urls = signPictures.stream().map(signPicture -> {
                        return signPicture.getUrl();
                    }).collect(Collectors.toList());
                    responseDTO.setSignPictureUrlList(urls);
                    String images = Joiner.on(",").join(urls);
                    responseDTO.setImages(images);

                    signResponseDTOS.add(responseDTO);
                }
                signRsponseListDTO.setSignResponseList(signResponseDTOS);//封装responseDTO

                signRsponseListDTOS.add(signRsponseListDTO); //封装responseDTO集合
            }
        }
        return signRsponseListDTOS;
    }



    /**
     * 查询当前登录用户某月的签到记录
     * @param dateStr
     * @return
     */
    @Override
    public List<SignResponseDTO> pagingSignCurrentUserByMonth(String dateStr) {

        //查询当前登录用户的信息
        SysCompanyUserDTO companyUserDTO = companyUserFeign.queryCompanyUserById(CurrentUserHolder.get().getCompanyUserId()).getData();

        //查询等钱登录用户某月的签到记录
        LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SignInfo::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SignInfo::getCompanyUserId,CurrentUserHolder.get().getCompanyUserId());
        wrapper.eq(SignInfo::getCreateMonth,dateStr);
        List<SignInfo> signInfos = signInfoMapper.selectList(wrapper);

        if(!CollectionUtils.isEmpty(signInfos)){
            ArrayList<SignResponseDTO> signResponseDTOS = new ArrayList<>();

            for (SignInfo signInfo : signInfos) {
                SignResponseDTO responseDTO = BeanHelper.copyProperties(signInfo, SignResponseDTO.class);

                //从redis中获取当日和当月签到次数
                String dayCountKey = CurrentUserHolder.get().getCompanyId() + "," + CurrentUserHolder.get().getCompanyUserId() + "," + signInfo.getCreateDate();
                String dayCount = (String) redisTemplate.opsForValue().get(dayCountKey);

                String monthCountKey = CurrentUserHolder.get().getCompanyId() + "," + CurrentUserHolder.get().getCompanyUserId() + "," + signInfo.getCreateMonth();
                String monthCount = (String) redisTemplate.opsForValue().get(monthCountKey);

                responseDTO.setDayCount(dayCount);
                responseDTO.setMonthCount(monthCount);
                responseDTO.setUsername(companyUserDTO.getUserName());

                //查询签到图片
                LambdaQueryWrapper<SignPicture> wrappr = new LambdaQueryWrapper<>();
                wrappr.eq(SignPicture::getSignId,signInfo.getId());
                List<SignPicture> signPictures = signPictureMapper.selectList(wrappr);
                List<String> urls = new ArrayList<>();
                for (SignPicture signPicture : signPictures) {
                    urls.add(signPicture.getUrl());
                }

                responseDTO.setSignPictureUrlList(urls);
                String images = StringUtils.join(urls.toArray(), ",");
                responseDTO.setImages(images);

                //签到时间处理
                String dateToStr = DateTimeUtil.dateToStr(signInfo.getCreateTime(), DateTimeUtil.STANDARD_FORMAT);
                responseDTO.setCreateTime(dateToStr);

                signResponseDTOS.add(responseDTO);
            }
            return signResponseDTOS;
        }
        return null;
    }
}
